package com.qiqidream.admin.security.filter;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.exceptions.ApiException;
import com.qiqidream.admin.common.config.EncodeConfig;
import com.qiqidream.admin.common.constant.StaticConstants;
import com.qiqidream.admin.common.utils.EncodeUtil;
import com.qiqidream.admin.common.utils.Multi.MultiReadHttpServletRequest;
import com.qiqidream.admin.security.entity.LoginUser;
import com.qiqidream.admin.security.login.AdminAuthenticationFailureHandler;
import com.qiqidream.admin.security.login.AdminAuthenticationSuccessHandler;
import com.qiqidream.admin.security.login.CusAuthenticationManager;
import com.qiqidream.admin.tools.model.entity.SysSetting;
import com.qiqidream.admin.tools.service.SysSettingService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义用户密码校验过滤器
 * @author QiQiDream
 * @since 2019/11/18 9:56
 */
@Component
public class AdminAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private SysSettingService sysSettingService;

    @Resource
    EncodeConfig encodeConfig;

    /**
     * @param authenticationManager:             认证管理器
     * @param adminAuthenticationSuccessHandler: 认证成功处理
     * @param adminAuthenticationFailureHandler: 认证失败处理
     */
    public AdminAuthenticationProcessingFilter(CusAuthenticationManager authenticationManager, AdminAuthenticationSuccessHandler adminAuthenticationSuccessHandler, AdminAuthenticationFailureHandler adminAuthenticationFailureHandler) {
        super(new AntPathRequestMatcher("/login", "POST"));
        this.setAuthenticationManager(authenticationManager);
        this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);
        this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        if (request.getContentType() == null || !request.getContentType().contains(StaticConstants.REQUEST_HEADERS_CONTENT_TYPE)) {
            throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType());
        }

        UsernamePasswordAuthenticationToken authRequest;
        try {
            MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
            LoginUser user;

            if (encodeConfig.getEnabled()) {
                JSONObject jsonObject = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest), JSONObject.class);
                user = JSONObject.parseObject(EncodeUtil.decrypt(jsonObject.getString("request")), LoginUser.class);
            } else {
                // 将前端传递的数据转换成jsonBean数据格式
                user = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest), LoginUser.class);
            }

            SysSetting sysSetting = sysSettingService.getOne(new LambdaQueryWrapper<SysSetting>().eq(SysSetting::getCode, "captcha"));

            if (sysSetting.getEnabled()) {

                if (ObjectUtils.isEmpty(user.getCaptcha())) {
                    throw new ApiException("验证码为空");
                }

                String key = StaticConstants.REDIS_CAPTCHA_KEY_PREFIX + user.getUuid();
                String captcha = stringRedisTemplate.opsForValue().get(key);

                if (ObjectUtils.isEmpty(captcha)) {
                    throw new ApiException("验证码不存在或已过期");
                }

                if (!captcha.equals(user.getCaptcha().trim().toLowerCase())) {
                    throw new ApiException("验证码错误");
                }
            }

            authRequest = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
            authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest));
        } catch (Exception e) {
            throw new AuthenticationServiceException(e.getMessage());
        }
        return this.getAuthenticationManager().authenticate(authRequest);
    }
}
